/**
 * 
 */
package soa.security.mgr.service.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.naming.Name;

import org.apache.commons.lang3.StringUtils;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import soa.security.Constants;
import soa.security.domain.Department;
import soa.security.domain.Group;
import soa.security.domain.Group.Groups;
import soa.security.domain.Organization;
import soa.security.domain.OrganizationUnit;
import soa.security.domain.Person;
import soa.security.exception.AdapterException;
import soa.security.exception.OrganizationException;
import soa.security.mgr.service.GroupMgrService;
import soa.security.util.BeanUtils;
import soa.security.util.JaxbUtils;

/**
 * @author Cre.Gu
 *
 */
@Service
public class GroupMgrServiceImpl extends BaseMgrServiceImpl implements
		GroupMgrService {
	protected final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(this.getClass());

	@Override
	public void addGroup(String organizationId, Group bean)
			throws OrganizationException {
		try {
			if (StringUtils.isBlank(bean.getBid())) {
				bean.setBid("GR" + findMaxNumber(Group.class));
			}
			validate(bean);
			validateOrganization(organizationId);

			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.GROUP);

			bean.setDn(bean.buildDn(unit.getDn()));
			groupDao.create(bean);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	@Override
	public void updateGroup(String organizationId, Group bean)
			throws OrganizationException {
		try {
			validateOrganization(organizationId);
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.GROUP);
			validateGroup(unit.getDn().toString(), bean.getBid());

			Group up = groupDao.findByPrimaryKey(unit.getDn()
					.toString(), bean.getBid());
			BeanUtils.copyPropertiesWithoutNull(bean, up);
			bean = up;
			
			validate(bean);

			bean.setDn(bean.buildDn(unit.getDn()));
			groupDao.update(bean);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	private void validate(Group d) {
		Assert.hasText(d.getBid(), "组编码不能为空");
		Assert.hasText(d.getName(), "组名称不能为空");

		BeanUtils.blank2Null(d);
	}

	@Override
	public List<Group> allGroups(String organizationId)
			throws OrganizationException {
		return allGroups(organizationId, null, false);
	}

	@Override
	public List<Group> allGroups(String organizationId,
			Map<String, Object> parameters, boolean subTree)
			throws OrganizationException {
		List<Group> results = new ArrayList<Group>();
		try {
			validateOrganization(organizationId);

			if (subTree) {
				List<Organization> oneOrg = oneOrg(organizationId);
				for (Organization or : oneOrg) {
					results.addAll(doAllGroups(or.getBid(), parameters));
				}
			} else {
				results = doAllGroups(organizationId, parameters);
			}

		} catch (Exception e) {
			wrapException(e);
		}
		return results;
	}

	protected List<Group> doAllGroups(String organizationId,
			Map<String, Object> parameters) {
		List<Group> results = new ArrayList<Group>();

		OrganizationUnit unit = gainOrganizationUnit(organizationId,
				Constants.GROUP);

		results = groupDao.allGroups(unit.getDn().toString(),
				defaultSearchScope, parameters);

		sortResult(results);
		return results;
	}

	@Override
	public List<Group> allGroups(List<Group> all, List<Group> deptGroups) {
		Iterator<Group> iter = all.iterator();
		while (iter.hasNext()) {
			Group p = iter.next();
			boolean re = true;
			for (Group person : deptGroups) {
				if (p.getBid().equals(person.getBid())) {
					re = false;
					break;
				}
			}

			if (re)
				iter.remove();
		}
		return all;
	}

	@Override
	public List<Group> getGroup(String organizationId, String groupId)
			throws OrganizationException {
		List<Group> list = new ArrayList<Group>();
		try {
			validateOrganization(organizationId);
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.GROUP);
			validateGroup(unit.getDn().toString(), groupId);

			Name dn = LdapNameBuilder.newInstance(unit.getDn())
					.add(Constants.BID, groupId).build();
			list.add(groupDao.findByDn(dn.toString()));

		} catch (Exception e) {
			wrapException(e);
		}
		return list;
	}

	@Override
	public boolean addPersons(String organizationId, String groupId,
			String personIds) throws OrganizationException {
		try {
			validateOrganization(organizationId);

			OrganizationUnit poUnit = gainOrganizationUnit(organizationId,
					Constants.GROUP);
			validateGroup(poUnit.getDn().toString(), groupId);

			Group group = groupDao.findByPrimaryKey(poUnit.getDn().toString(),
					groupId);

			String[] pids = StringUtils.split(personIds, ",");
			for (String pid : pids) {
				OrganizationUnit unit = gainOrganizationUnit(organizationId,
						Constants.PERSON);

				validatePerson(unit.getDn().toString(), pid);
				groupDao.addAttrName(group.getDn(), Constants.PERSONS,
						personDao
								.findByPrimaryKey(unit.getDn().toString(), pid)
								.getDn().toString());
				// groupDao.addPersons(group, personDao.findByPrimaryKey(unit
				// .getDn().toString(), pid));

			}

			return true;
		} catch (Exception e) {
			wrapException(e);
		}
		return false;
	}

	@Override
	public boolean removePersons(String organizationId, String groupId,
			String personIds) throws OrganizationException {
		try {
			validateOrganization(organizationId);

			OrganizationUnit poUnit = gainOrganizationUnit(organizationId,
					Constants.GROUP);
			validateGroup(poUnit.getDn().toString(), groupId);

			Group group = groupDao.findByPrimaryKey(poUnit.getDn().toString(),
					groupId);

			String[] pids = StringUtils.split(personIds, ",");
			for (String pid : pids) {
				OrganizationUnit unit = gainOrganizationUnit(organizationId,
						Constants.PERSON);

				validatePerson(unit.getDn().toString(), pid);
				groupDao.removeAttrName(group.getDn(), Constants.PERSONS,
						personDao
								.findByPrimaryKey(unit.getDn().toString(), pid)
								.getDn().toString());
				// groupDao.removePersons(group, personDao.findByPrimaryKey(unit
				// .getDn().toString(), pid));

			}

			return true;
		} catch (Exception e) {
			wrapException(e);
		}
		return false;
	}

	@Override
	public List<Person> allPersons(String organizationId, String groupId)
			throws OrganizationException {
		List<Person> list = new ArrayList<Person>();
		try {
			List<String> pids = super.groupPersons(organizationId, groupId);

			for (String string : pids) {
				list.add(personDao.findByDn(string));
			}
		} catch (Exception e) {
			wrapException(e);
		}
		return list;
	}

	@Override
	public boolean addSubGroups(String organizationId, String groupId,
			String subGroupIds) throws OrganizationException {
		try {
			validateOrganization(organizationId);

			OrganizationUnit poUnit = gainOrganizationUnit(organizationId,
					Constants.GROUP);
			validateGroup(poUnit.getDn().toString(), groupId);

			Group group = groupDao.findByPrimaryKey(poUnit.getDn().toString(),
					groupId);

			String[] pids = StringUtils.split(subGroupIds, ",");
			for (String pid : pids) {
				OrganizationUnit unit = gainOrganizationUnit(organizationId,
						Constants.GROUP);

				validateGroup(unit.getDn().toString(), pid);
				groupDao.addAttrName(group.getDn(), Constants.CHILDREN,
						groupDao.findByPrimaryKey(unit.getDn().toString(), pid)
								.getDn().toString());
				// groupDao.addSubGroups(group,
				// groupDao.findByPrimaryKey(unit.getDn().toString(), pid));

			}

			return true;
		} catch (Exception e) {
			wrapException(e);
		}
		return false;
	}

	@Override
	public boolean removeSubGroups(String organizationId, String groupId,
			String subGroupIds) throws OrganizationException {
		try {
			validateOrganization(organizationId);

			OrganizationUnit poUnit = gainOrganizationUnit(organizationId,
					Constants.GROUP);
			validateGroup(poUnit.getDn().toString(), groupId);

			Group group = groupDao.findByPrimaryKey(poUnit.getDn().toString(),
					groupId);

			String[] pids = StringUtils.split(subGroupIds, ",");
			for (String pid : pids) {
				OrganizationUnit unit = gainOrganizationUnit(organizationId,
						Constants.GROUP);

				validateGroup(unit.getDn().toString(), pid);
				groupDao.removeAttrName(group.getDn(), Constants.CHILDREN,
						groupDao.findByPrimaryKey(unit.getDn().toString(), pid)
								.getDn().toString());
				// groupDao.removeSubGroups(group,
				// groupDao.findByPrimaryKey(unit.getDn().toString(), pid));

			}

			return true;
		} catch (Exception e) {
			wrapException(e);
		}
		return false;
	}

	@Override
	public List<Group> allSubGroups(String organizationId, String groupId)
			throws OrganizationException {
		List<Group> list = new ArrayList<Group>();
		try {
			if (StringUtils.isBlank(groupId))
				return list;

			validateOrganization(organizationId);
			OrganizationUnit deUnit = gainOrganizationUnit(organizationId,
					Constants.GROUP);
			validateGroup(deUnit.getDn().toString(), groupId);

			List<String> pids = groupDao.allAttrName(
					groupDao.findByPrimaryKey(deUnit.getDn().toString(),
							groupId).getDn(), Constants.CHILDREN);

			// allSubGroups(groupDao
			// .findByPrimaryKey(deUnit.getDn().toString(), groupId));

			for (String string : pids) {
				list.add(groupDao.findByDn(string));
			}
		} catch (Exception e) {
			wrapException(e);
		}
		return list;
	}

	@Override
	public List<Group> adapt(String xml) throws AdapterException {
		try {
			Groups bs = JaxbUtils.xml2Object(xml, Groups.class);
			return bs.getGroup();

		} catch (Exception e) {
			if (log.isDebugEnabled())
				log.debug("格式转换错误", e);
			throw new AdapterException(AdapterException.ERROR_01);
		}
	}

	@Override
	public String unadapt(List<Group> list) throws AdapterException {
		try {
			Groups bs = new Groups();
			bs.addAll(list);

			return JaxbUtils.object2Xml(bs, Groups.class);
		} catch (Exception e) {
			if (log.isDebugEnabled())
				log.debug("格式转换错误", e);
			throw new AdapterException(AdapterException.ERROR_01);
		}
	}

	@Override
	public Group findByDn(String dn) {
		try {
			return groupDao.findByDn(dn);

		} catch (Exception e) {
			printException(e);
			if (log.isDebugEnabled())
				log.debug("错误信息", e);

			return null;
		}
	}

	@Override
	public boolean deleteByDn(String dn) throws OrganizationException {
		try {
			groupDao.deleteByDn(dn);
			return true;
		} catch (Exception e) {
			printException(e);
			if (log.isDebugEnabled())
				log.debug("错误信息", e);

			return false;
		}
	}

	@Override
	public List<Department> findDepartments(String organizationId, String dn) {
		List<Department> result = new ArrayList<Department>();
		try {
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.DEPARTMENT);
			return departmentDao.findAllByAttr(unit.getDn().toString(),
					defaultSearchScope, Constants.POSITIONS, dn);

		} catch (Exception e) {
			printException(e);
		}
		return result;
	}

	@Override
	public void addGroup4Mgr(String organizationId, Group model,
			String departmentDns, String personDns, String subGroupDns) {
		try {
			addGroup(organizationId, model);

			addOrRemoveDepartments4Mgr(organizationId, model, departmentDns);
			addOrRemovePersons4Mgr(organizationId, model, personDns);
			addOrRemoveSubs4Mgr(organizationId, model, subGroupDns);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	@Override
	public void updateGroup4Mgr(String organizationId, Group model,
			String departmentDns, String personDns, String subGroupDns) {
		try {
			updateGroup(organizationId, model);

			addOrRemoveDepartments4Mgr(organizationId, model, departmentDns);
			addOrRemovePersons4Mgr(organizationId, model, personDns);
			addOrRemoveSubs4Mgr(organizationId, model, subGroupDns);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	private void addOrRemoveDepartments4Mgr(String organizationId, Group group,
			String departmentDns) {
		// 原来的personIds
		List<String> origs = allDepartmentsDns(findDepartments(organizationId,
				Constants.GROUPS, group.getDn().toString()));
		// form 提交的personIds
		List<String> forms = formIds(departmentDns);

		// 要增加的personIds
		List<String> adds = addIds(origs, forms);
		// 要删除的personIds
		List<String> rems = removeIds(origs, forms);

		ldapAddAttrName(adds, Constants.GROUPS, group.getDn().toString());
		ldapRemoveAttrName(rems, Constants.GROUPS, group.getDn().toString());
	}

	private void addOrRemovePersons4Mgr(String organizationId, Group group,
			String personDns) {
		// 原来的personIds
		List<String> origs = groupDao.allAttrName(group.getDn(),
				Constants.PERSONS);
		// allPersons(group);
		// form 提交的personIds
		List<String> forms = formIds(personDns);

		// 要增加的personIds
		List<String> adds = addIds(origs, forms);
		// 要删除的personIds
		List<String> rems = removeIds(origs, forms);

		DirContextOperations context = ldapTemplate
				.lookupContext(group.getDn());

		for (String string : adds) {
			context.addAttributeValue(Constants.PERSONS, string);
		}
		for (String string : rems) {
			context.removeAttributeValue(Constants.PERSONS, string);
		}
		ldapTemplate.modifyAttributes(context);
	}

	private void addOrRemoveSubs4Mgr(String organizationId, Group group,
			String subGroupDns) {
		// 原来的personIds
		List<String> origs = groupDao.allAttrName(group.getDn(),
				Constants.CHILDREN);

		// groupDao.allSubGroups(group);
		// form 提交的personIds
		List<String> forms = formIds(subGroupDns);

		// 要增加的personIds
		List<String> adds = addIds(origs, forms);
		// 要删除的personIds
		List<String> rems = removeIds(origs, forms);

		DirContextOperations context = ldapTemplate
				.lookupContext(group.getDn());

		for (String string : adds) {
			context.addAttributeValue(Constants.CHILDREN, string);
		}
		for (String string : rems) {
			context.removeAttributeValue(Constants.CHILDREN, string);
		}
		ldapTemplate.modifyAttributes(context);
	}

	@Override
	public List<Group> findParents(String organizationId, String groupDn,
			boolean recursive) {
		List<Group> result = new ArrayList<Group>();
		try {
			if (StringUtils.isBlank(groupDn))
				return result;
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.GROUP);
			List<Group> list = groupDao.findAllByAttr(unit.getDn().toString(),
					defaultSearchScope, Constants.CHILDREN, groupDn);

			result.addAll(list);

			if (recursive)
				for (Group group : list) {
					result.addAll(findParents(organizationId, group.getDn()
							.toString(), recursive));
				}
		} catch (Exception e) {
			printException(e);
		}
		return result;
	}

	@Override
	public List<Group> wrapGroups(List<Group> groups) {
		for (Group group : groups) {
			try {
				List<String> pdns = groupDao.allAttrName(group.getDn(),
						Constants.PERSONS);

				// allPersons(group);
				String[] names = new String[pdns.size()];
				int i = 0;

				for (String string : pdns) {
					Person per = personDao.findByDn(string);
					names[i++] = per.getName();
				}
				group.setPersonName(StringUtils.join(names, ","));
			} catch (Exception e) {
			}
		}
		return groups;
	}

	@Override
	public void remove(String organizationId, String dn) {
		String[] dns = StringUtils.split(dn, ";");
		if (dns == null)
			return;

		for (String string : dns) {
			DirContextOperations context = ldapTemplate.lookupContext(string);

			context.setAttributeValue(Constants.DELETED, Constants.TRUE);
			ldapTemplate.modifyAttributes(context);

			// 删除关系
			// 部门，父用户组
			List<String> rems = new ArrayList<String>();
			List<String> rems2 = new ArrayList<String>();
			rems.addAll(allDepartmentsDns(findDepartments(organizationId,
					Constants.GROUPS, dn)));
			ldapRemoveAttrName(rems, Constants.GROUPS, dn);

			rems2.addAll(allGroupsDns(findParents(organizationId, dn, true)));
			ldapRemoveAttrName(rems2, Constants.CHILDREN, dn);
		}
	}
}
